package com.mikelouis.test.scala.proginscala.chapter28

/**
 * These point classes have excellent equals and hashCode methods.
 * They rely on an canEqual method.
 * Created by yuazhu on 2/26/2015.
 */
object Points8 {

  class Point(val x: Int, val y: Int) {
    override def hashCode = 41 * (41 + x) + y

    override def equals(other: Any) = other match {
      case that: Point =>
        (that canEqual this) &&
          (this.x == that.x) && (this.y == that.y)
      case _ =>
        false
    }

    def canEqual(other: Any) = other.isInstanceOf[Point]
  }

  object Color extends Enumeration {
    val Red, Orange, Yellow, Green, Blue, Indigo, Violet = Value
  }

  class ColoredPoint(x: Int, y: Int, val color: Color.Value)
    extends Point(x, y) {

    override def hashCode = 41 * super.hashCode + color.hashCode

    override def equals(other: Any) = other match {
      case that: ColoredPoint =>
        (that canEqual this) &&
          super.equals(that) && this.color == that.color
      case _ =>
        false
    }

    override def canEqual(other: Any) =
      other.isInstanceOf[ColoredPoint]
  }

  def main(args: Array[String]) {
    val p = new Point(1, 2)
    val redp = new ColoredPoint(1, 2, Color.Red)
    val bluep = new ColoredPoint(1, 2, Color.Blue)
    println(redp == p)
    println(p == bluep)
    println(redp == bluep)

    val pAnon = new Point(1, 1) { override val y = 2 }
    println(p == pAnon)

    // pAnon is anonymous class of Point and no canEqual method is overrided, so pAnon is equal to p
    // which break LSP rule
    val cp = new ColoredPoint(1, 2, Color.Indigo)
    val coll = List(p)
    println(coll contains p)
    println(coll contains cp)
    println(coll contains pAnon)
  }

}
